package org.carabiner.infinitest;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import org.carabiner.infinitest.depgraph.ClassFileFilter;

public class FileChangeDetector
{
  private List<File> classDir;
  private Map<File, Long> timestampIndex;

  public FileChangeDetector(List<File> classDirList)
  {
    classDir = classDirList;
    timestampIndex = new HashMap<File, Long>();
  }

  public FileChangeDetector(File classDirectory)
  {
    this(Arrays.asList(new File[]{classDirectory}));
  }

  public Set<File> findChangedFiles() throws IOException
  {
    return findFiles(classDir.toArray(new File[classDir.size()]));
  }

  private Set<File> findFiles(File[] classesOrDirectories) throws IOException
  {
    Set<File> changedFiles = new HashSet<File>();
    for (int i = 0; i < classesOrDirectories.length; i++)
    {
      File classfileOrDirectory = classesOrDirectories[i];
      if (classfileOrDirectory.isDirectory())
      {
        File[] children = classfileOrDirectory.listFiles(new ClassFileFilter());
        changedFiles.addAll(findFiles(children));
      }
      else
      {
        if (ClassFileFilter.isClassFile(classfileOrDirectory))
        {
          Long timestamp = timestampIndex.get(classfileOrDirectory);
          if (timestamp == null)
            InfinitestUtils.log(Level.FINE, "New class file added to index " + classfileOrDirectory);
          if (timestamp == null || classfileOrDirectory.lastModified() != timestamp)
          {
            timestampIndex.put(classfileOrDirectory, classfileOrDirectory.lastModified());
            changedFiles.add(classfileOrDirectory);
            InfinitestUtils.log(Level.FINE, "Class file added to changelist " + classfileOrDirectory);
          }
        }
      }
    }
    return changedFiles;
  }

  public void clear()
  {
    timestampIndex.clear();
  }

}
